package com.missyoubug.easyjtest.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.missyoubug.easyjtest.entity.*;
import com.missyoubug.easyjtest.service.EasyTestService;
import com.missyoubug.easyjtest.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import java.lang.reflect.*;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Controller
@RequestMapping
public class MainController {

    @Autowired
    private EasyTestService easyTestService;
    @Autowired
    private ApplicationContext context;

    @GetMapping(value = "/test")
    public String test() {
        return "search";
    }


    @GetMapping(value = "/invokeMethod")
    @ResponseBody
    public Object easyTest(@RequestParam("data") String jsonData) {
        try {
            System.out.println(jsonData);

            // 解析 JSON 数据
            JSONObject params = JSONObject.parseObject(jsonData);
            String className = (String) params.get("className");
            String methodName = (String) params.get("methodName");
            String parameter = params.get("parameter").toString();
            String parameterStr = (String) params.get("parameterTypes");
            String msg = (String) params.get("msg");

            // 获取Spring中注册的Service Bean
            Object ret;

            JSONArray parameterTypes = JSONArray.parseArray(parameterStr);
            Class[] paramsTypes = new Class[parameterTypes.size()];

            for (int i = 0; i < parameterTypes.size(); i++) {
                JSONObject jsonObject = JSONObject.parseObject(parameterTypes.get(i).toString());
                Class<?> aClass = TypeResolver.resolveType(jsonObject.getString("parameterType"));
                paramsTypes[i] = aClass;
            }

            final Object serviceBean = ApplicationContextHelper.getBean(toLowerCaseFirstOne(className));

            Method method = ReflectUtil.getMethod(serviceBean.getClass(), Boolean.TRUE, methodName, paramsTypes);


            // 使用Fastjson将JSON字符串转换为Map
            List<Object> paramsArr = paramsChecker(method, parameter);

            if (null != method) {
                Class[] paramType = method.getParameterTypes();

                // 请求时间
                Instant start = Instant.now();

                // 调用Service层的方法
                if (ObjectUtil.isEmpty(paramType)) {
                    ret = ReflectUtil.invoke(serviceBean, methodName);
                } else {
                    ret = ReflectUtil.invoke(serviceBean, methodName, paramsArr.toArray());

                }
                System.out.println("测试成功 ——————》"+jsonData);
                EasyTestInfoEntity entity = new EasyTestInfoEntity();
                entity.setBeanName(className);
                entity.setMethodName(methodName);
                entity.setParameterTypes(parameterStr);
                entity.setMethodParameter(parameter);
                entity.setMsg(EmptyChecker.isEmpty(msg) ? "测试" : msg);
                entity.setAddTime(LocalDateTime.now());
                entity.setRequestData(jsonData);
                easyTestService.insertInvocation(entity);
                // 打印接口请求时间
                Instant end = Instant.now();
                printExecutionDetails(start, end);

                return ret;
            } else {
                // 创建一个RedirectView对象
                RedirectView redirectView = new RedirectView();
                redirectView.setUrl("/err");
                redirectView.setStatusCode(HttpStatus.FOUND);  // 设置HTTP状态码，默认是302

                // 返回ModelAndView对象
                return new ModelAndView(redirectView);
            }
        } catch (Throwable e) {
            e.printStackTrace();
            return "程序写错了，查查日志吧";
        }

    }

    private void printExecutionDetails(Instant start, Instant end) {
        // 计算耗时
        Duration duration = Duration.between(start, end);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
                .withZone(ZoneId.systemDefault());

        String startFormatted = formatter.format(start);
        String endFormatted = formatter.format(end);

        System.out.println("beginTime=" + startFormatted + ",End Time =" + endFormatted + ",Request Duration = " + duration.toMillis() + " ms");
    }

    private List<Object> paramsChecker(Method method, String parameter) {
        // 使用Fastjson将JSON字符串转换为Map
        JSONObject jsonMap = JSON.parseObject(parameter);
        List<Object> paramsArr = new ArrayList<>();
        Class<?>[] paramTypes = method.getParameterTypes();
        Type[] genericParamTypes = method.getGenericParameterTypes();

        for (int i = 0; i < paramTypes.length; i++) {
            String paramName = jsonMap.keySet().toArray(new String[0])[i];
            Object value = jsonMap.get(paramName);

            if (value == null) {
                throw new IllegalArgumentException("Missing required parameter: " + paramName);
            }

            Class<?> type = paramTypes[i];

            if (type.isPrimitive() || type == Integer.class || type == Long.class ||
                    type == Double.class || type == Float.class || type == Boolean.class ||
                    type == String.class || type == LocalDateTime.class) {
                // Fastjson can handle these types directly
                paramsArr.add(JSON.parseObject(JSON.toJSONString(value), type));
            } else if (Collection.class.isAssignableFrom(type)) {
                Type genericType = genericParamTypes[i];
                // 处理集合类型，如List<T>
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pType = (ParameterizedType) genericType;
                    Class<?> elementType = (Class<?>) pType.getActualTypeArguments()[0];
                    Collection<?> collectionValue = JSON.parseArray(JSON.toJSONString(value), elementType);
                    paramsArr.add(collectionValue);
                } else {
                    throw new IllegalArgumentException("Collection parameter type is not properly defined.");
                }
            } else {
                // 对于其他复杂对象类型
                Object paramValue = JSON.toJavaObject((JSONObject) value, type);
                paramsArr.add(paramValue);
            }
        }

        return paramsArr;
    }


    /**
     * 首字母转小写
     *
     * @param s
     * @return
     */
    public String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }


    @PostMapping("/search")
    @ResponseBody
    public Message<EasyTestBeanMsgVO> searchBean(String beanName) {
        Object bean;
        try {
            bean = ApplicationContextHelper.getBean(toLowerCaseFirstOne(beanName));
        } catch (org.springframework.beans.factory.NoSuchBeanDefinitionException e) {
            return Messages.failed(Code.NOT_DEFINED.getValue(), beanName);
        }
        EasyTestBeanMsgVO beanInfos = new EasyTestBeanMsgVO();
        Method[] methods = bean.getClass().getDeclaredMethods();
        List<EasyTestBeanMethodVO> methodVOList = new ArrayList<>(10);
        for (Method method : methods) {
            EasyTestBeanMethodVO methodVO = new EasyTestBeanMethodVO();
            System.out.println("方法名：" + method.getName());
            methodVO.setMethodName(method.getName());
            Parameter[] parameters = method.getParameters();
            if (parameters.length == 0) {
                System.out.println("此方法无参数");
            }
            List<EasyTestBeanParameterVO> params = new LinkedList<>();
            for (Parameter parameter : parameters) {
                String name = parameter.getName();
                Type genericType = parameter.getParameterizedType();
                String parameterTypeName = parameter.getType().getName();
                String parameterTypeInfoName = genericType.getTypeName();
                String converterStr = converterStr(parameterTypeInfoName);

                EasyTestBeanParameterVO beanParameter = new EasyTestBeanParameterVO();
                beanParameter.setParameterName(name);
                beanParameter.setParameterType(parameterTypeName);
                beanParameter.setParameterTypeStr(converterStr);
                params.add(beanParameter);
                System.out.println("参数名：" + name + ",参数类型：" + parameterTypeName);
            }
            methodVO.setParameterList(params);
            methodVOList.add(methodVO);
        }
        beanInfos.setBeanName(beanName);
        beanInfos.setMethods(methodVOList);
        return Messages.success(beanInfos);
    }


    private String converterStr(String str) {
        return str.replace("<", "&lt;").replace(">", "&gt;");
    }

    @GetMapping("/middleman")
    public String middleman(@RequestParam("classData") String classData, Model model) {
        if (EmptyChecker.isEmpty(classData)) {
            return "/errer";
        }
        try {
            JSONObject jsonObject = JSON.parseObject(classData);
            String beanName = jsonObject.getString("beanName");
            String methodName = jsonObject.getString("methodName");
            JSONArray parameter = JSON.parseArray(jsonObject.get("parameter").toString());


            Object bean = context.getBean(toLowerCaseFirstOne(beanName));

            Class[] paramsTypes = new Class[parameter.size()];

            for (int i = 0; i < parameter.size(); i++) {
                JSONObject paramsJsonObject = JSON.parseObject(parameter.get(i).toString());
                String parameterType = (String) paramsJsonObject.get("parameterType");
                Class<?> aClass = TypeResolver.resolveType(parameterType);
                paramsTypes[i] = aClass;
            }
            Method method = ReflectUtil.getMethod(bean.getClass(), Boolean.TRUE, methodName, paramsTypes);

            Parameter[] parameters = method.getParameters();
            JSONObject parametersJson = generateRandomParameters(parameters);

            EasyTestEntity testBean = easyTestService.getAllInvocations();
            EasyTestInfoEntity beanInfo = new EasyTestInfoEntity();
            beanInfo.setBeanName(beanName);
            beanInfo.setMethodName(methodName);
            beanInfo.setMethodParameter(parametersJson.toJSONString());
            beanInfo.setParameterTypes(parameter.toJSONString());
            testBean.setMemoryInfo(beanInfo);

            model.addAttribute("beanInfo", testBean);
        } catch (Throwable e) {
            e.printStackTrace();
            return "/errer";
        }
        return "/test";
    }


    private JSONObject generateRandomParameters(Parameter[] parameters) {

        JSONObject jsonObject = new JSONObject();
        for (Parameter parameter : parameters) {
            Object obj = repeater(parameter);
            jsonObject.put(parameter.getName(), obj);
        }
        return jsonObject;
    }

    private Object repeater(Parameter parameter) {
        Type genericType = parameter.getParameterizedType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) genericType;
            System.out.println("Raw type: " + pType.getRawType());
            Class<?> genericClazz = (Class<?>) pType.getActualTypeArguments()[0];
            Object fieldValue = generateRandomValue(genericClazz);
            JSONArray jsonArray = new JSONArray();
            jsonArray.add(fieldValue);
            return jsonArray;
        } else {
            return generateRandomValue(parameter.getType());
        }
    }

    private static final Random random = new Random();

    private Object generateRandomValue(Class<?> type) {
        if (type == int.class || type == Integer.class) {
            return random.nextInt(100);
        } else if (type == long.class || type == Long.class) {
            return random.nextLong();
        } else if (type == double.class || type == Double.class) {
            return random.nextDouble() * 100;
        } else if (type == float.class || type == Float.class) {
            return random.nextFloat() * 100;
        } else if (type == boolean.class || type == Boolean.class) {
            return random.nextBoolean();
        } else if (type == String.class) {
            return "randomString" + random.nextInt(100);
        } else if (type == LocalDateTime.class) {
            return LocalDateTime.now();
        } else if (List.class.isAssignableFrom(type)) {
            JSONArray jsonArray = new JSONArray();
            JSONObject objectArr = getObjectArr(type);
            jsonArray.add(objectArr);
            return jsonArray;
        } else {

            return getObjectArr(type);
        }
    }

    private JSONObject getObjectArr(Class<?> type) {
        try {
            JSONObject jsonObject = new JSONObject();
            // 对于复杂类型，递归生成随机值
            for (Field field : type.getDeclaredFields()) {
                field.setAccessible(true);
                Type genericType = field.getGenericType();
                if (genericType == null) continue;
                //是list
                if (genericType instanceof ParameterizedType) {

                    ParameterizedType pt = (ParameterizedType) genericType;
                    //得到泛型里的class类型对象
                    Class<?> genericClazz = (Class<?>) pt.getActualTypeArguments()[0];
                    Object fieldValue = generateRandomValue(genericClazz);
//                        field.set(instance, fieldValue);
                    JSONArray jsonArray = new JSONArray();
                    jsonArray.add(fieldValue);
                    jsonObject.put(field.getName(), jsonArray);

                } else {
                    Class<?> fieldType = field.getType();
                    Object fieldValue = generateRandomValue(fieldType);
//                    field.set(instance, fieldValue);
                    jsonObject.put(field.getName(), fieldValue);
                }

            }
//            return instance;
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}






